#include "kaeromanager.h"
#include "QWidget"
#include "QApplication"

#ifdef Q_OS_WIN
#include <dwmapi.h>
#endif

struct _WINCOMPATTRDATA
{
	DWORD attribute;
	PVOID pData;
	ULONG dataSize;
};

KAeroManager::KAeroManager()
{
}

bool KAeroManager::resolveLibs()
{
	if (QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
		return false;

#ifdef Q_OS_WIN
    if (!pDwmIsCompositionEnabled && !dwmLib)
	{
		WCHAR AppPath[MAX_PATH] = {0};
		GetSystemDirectoryW(AppPath, MAX_PATH);
		QString dllPath = QString::fromUtf16((char16_t*)AppPath);
		dllPath += "\\dwmapi";

		dwmLib.reset(new QLibrary(dllPath));
		pDwmIsCompositionEnabled =(PtrDwmIsCompositionEnabled)dwmLib->resolve("DwmIsCompositionEnabled");
		pDwmenableBlurBehindWindow = (PtrDwmEnableBlurBehindWindow)dwmLib->resolve("DwmEnableBlurBehindWindow");
		pDwmExtendFrameIntoClientArea = (PtrDwmExtendFrameIntoClientArea)dwmLib->resolve("DwmExtendFrameIntoClientArea");
		pDwmGetColorizationColor = (PtrDwmGetColorizationColor)dwmLib->resolve("DwmGetColorizationColor");
		pDwmGetWindowAttribute = (PtrDwmGetWindowAttribute)dwmLib->resolve("DwmGetWindowAttribute");
		pDwmDefWindowProc = (PtrDwmDefWindowProc)dwmLib->resolve("DwmDefWindowProc");

		HMODULE hUser = GetModuleHandleW(L"user32.dll");
		pDwmGetSharedSurface
			= (PtrDwmGetSharedSurface)GetProcAddress(hUser, "DwmGetDxSharedSurface");
		pSetWindowCompositionAttribute
			= (PtrSetWindowCompositionAttribute)GetProcAddress(hUser, "SetWindowCompositionAttribute");
    }
#endif
	return pDwmIsCompositionEnabled != NULL;
}

bool KAeroManager::isCompositionEnabled()
{
#ifdef Q_OS_WIN
    if (resolveLibs())
	{
        HRESULT hr = S_OK;
        BOOL isEnabled = false;
        hr = pDwmIsCompositionEnabled(&isEnabled);
        if (SUCCEEDED(hr))
            return isEnabled;
    }
#endif
    return false;
}

bool KAeroManager::isSupportBlurWindow()
{
#ifdef Q_OS_WIN
	if(QSysInfo::WV_WINDOWS8 == QSysInfo::windowsVersion() || 
		//QSysInfo::WV_WINDOWS8_1 == QSysInfo::windowsVersion() ||
		QSysInfo::WV_VISTA > QSysInfo::windowsVersion())
		return false;
	return true;
#endif
	return false;
}

bool KAeroManager::enableBlurBehindWindow(QWidget *widget, bool enable)
{
	if (!widget) 
		return false;

	bool result = false;
#ifdef Q_OS_WIN
	if (resolveLibs())
	{
		OSVERSIONINFOW osver;
		osver.dwOSVersionInfoSize = sizeof(osver);
		GetVersionExW(&osver);

		if(10 == osver.dwMajorVersion)
		{
			result = setBlurCompositionAttribute(widget, enable);
		}
		else
		{
			DWM_BLURBEHIND bb = {0};
			HRESULT hr = S_OK;
			bb.fEnable = enable;
			bb.dwFlags = DWM_BB_ENABLE;
			bb.hRgnBlur = NULL;
			hr = pDwmenableBlurBehindWindow((HWND)widget->winId(), &bb);
			if (SUCCEEDED(hr))
			{
				result = true;
			}
		}
	}
	if (result)
	{
		widget->setAttribute(Qt::WA_TranslucentBackground, enable);
		widget->setAttribute(Qt::WA_NoSystemBackground, enable);
	}
#endif
	return result;
}

bool KAeroManager::extendFrameIntoClientArea(QWidget *widget, int left, int right, int top, int bottom)
{
	if (!widget) 
		return false;

	bool result = false;
#ifdef Q_OS_WIN
	if (resolveLibs())
	{
		HRESULT hr = S_OK;
		MARGINS m = {left, right, top, bottom};
		hr = pDwmExtendFrameIntoClientArea((HWND)widget->winId(), &m);
		if (SUCCEEDED(hr)) 
			result = true;
	}
	widget->setAttribute(Qt::WA_TranslucentBackground, result);
	widget->setAttribute(Qt::WA_NoSystemBackground, result);
#endif
	return result;
}

bool KAeroManager::extendFrameIntoClientArea(__in HWND hWnd, int left, int right, int top, int bottom)
{
	if (!hWnd) 
		return false;

	bool result = false;
#ifdef Q_OS_WIN
	if (resolveLibs())
	{
		HRESULT hr = S_OK;
		MARGINS m = {left, right, top, bottom};
		hr = pDwmExtendFrameIntoClientArea(hWnd, &m);
		if (SUCCEEDED(hr)) 
			result = true;
	}
#endif
	return result;
}

bool KAeroManager::extendFrameIntoClientArea(QWidget *w, QMargins m)
{
	return extendFrameIntoClientArea(w, m.left(), m.right(), m.top(), m.bottom());
}

QColor KAeroManager::colorizatinColor()
{
	QColor resultColor = QApplication::palette().window().color();
#ifdef Q_OS_WIN
	if (resolveLibs())
	{
		DWORD color = 0;
		BOOL opaque = FALSE;
		HRESULT hr = S_OK;
		hr = pDwmGetColorizationColor(&color, &opaque);
		if (SUCCEEDED(hr))
			resultColor = QColor(color);
	}
#endif
	return resultColor;
}

bool KAeroManager::setBlurCompositionAttribute(QWidget *w, bool bOn)
{
#ifdef Q_OS_WIN
#define WCA_ACCENT_POLICY  19

	if(QSysInfo::windowsVersion() <= QSysInfo::WV_WINDOWS8)
		return false;

	if (resolveLibs() && NULL != w && NULL != pSetWindowCompositionAttribute)
	{
		enum ACCENT_STATE
		{
			ACCENT_DISABLED = 0,
			ACCENT_ENABLE_GRADIENT = 1,
			ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
			ACCENT_ENABLE_BLURBEHIND = 3,
			ACCENT_INVALID_STATE = 4
		};

		struct ACCENT_POLICY
		{
			ACCENT_STATE AccentState;
			DWORD AccentFlags;
			DWORD GradientColor;
			DWORD AnimationId;
		};

		ACCENT_POLICY accent = { bOn ? ACCENT_ENABLE_BLURBEHIND : ACCENT_DISABLED, 0, 0, 0 }; 
		_WINCOMPATTRDATA data;
		data.attribute = WCA_ACCENT_POLICY;
		data.pData = &accent;
		data.dataSize = sizeof(accent);

		BOOL bRes = pSetWindowCompositionAttribute((HWND)w->winId(), &data);
		return bRes;
	}
#endif
	return false;
}

QRect KAeroManager::getWindowSystemButtonRect(QWidget *w)
{
#ifdef Q_OS_WIN
	if (resolveLibs() && NULL != w)
	{
		RECT r;
		HRESULT hr = S_OK;
		hr = pDwmGetWindowAttribute((HWND)w->winId(), DWMWA_CAPTION_BUTTON_BOUNDS, &r, sizeof(r));
 		if (SUCCEEDED(hr))
 			return QRect(r.left, r.top, r.right - r.left, r.bottom - r.top);
	}
#endif
	return QRect();
}

HANDLE KAeroManager::getSharedSurfaceHandle(__in HWND hWnd)
{
#ifdef Q_OS_WIN
	if (resolveLibs() && NULL != hWnd && NULL != pDwmGetSharedSurface)
	{
		HANDLE hSurface = NULL;
		UINT64 nAdapterLuid = 0;
		DWORD dwFmtWindow = 0; 
		DWORD dwPresentFlags = 0;
		UINT64 nWin32kUpdateId = 0;
		BOOL bRes = pDwmGetSharedSurface(hWnd, &hSurface, &nAdapterLuid, 
			&dwFmtWindow, &dwPresentFlags, &nWin32kUpdateId);
		if (bRes && hSurface)
			return hSurface;
	}
#endif
	return NULL;
}

bool KAeroManager::DwmDefWindowProc(__in HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, __out LRESULT *plResult)
{
#ifdef Q_OS_WIN
	if (resolveLibs())
	{
		return pDwmDefWindowProc(hWnd, msg, wParam, lParam, plResult);
	}
#endif
	return false;
}

PtrDwmIsCompositionEnabled KAeroManager::pDwmIsCompositionEnabled;
PtrDwmEnableBlurBehindWindow KAeroManager::pDwmenableBlurBehindWindow;
PtrDwmExtendFrameIntoClientArea KAeroManager::pDwmExtendFrameIntoClientArea;
PtrDwmGetColorizationColor KAeroManager::pDwmGetColorizationColor;
PtrDwmGetWindowAttribute KAeroManager::pDwmGetWindowAttribute;
PtrDwmDefWindowProc KAeroManager::pDwmDefWindowProc;
PtrDwmGetSharedSurface KAeroManager::pDwmGetSharedSurface;
PtrSetWindowCompositionAttribute KAeroManager::pSetWindowCompositionAttribute;
QScopedPointer<QLibrary> KAeroManager::dwmLib;
